// Copyright (C) 2012 Yury Bychenkov (http://bychenkov.com).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//  - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//  - Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//  - Neither the name of Yury Bychenkov nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "schema.h"

Logger Schema::logger("Schema");

uint Schema::parseType(const char* name) {
	if (0 == strcmp(name, "string")) {
		return STRING;
	} else if (0 == strcmp(name, "integer")) {
		return INTEGER;
	} else if (0 == strcmp(name, "decimal")) {
		return DECIMAL;
	}

	return UNKNOWN;
}

const char* Schema::formatType(uint type, bool full) {
	switch (type) {
		case STRING:  return full ? "string"  : "str";
		case INTEGER: return full ? "integer" : "int";
		case DECIMAL: return full ? "decimal" : "dec";
	}
	return full ? "unknown" : "unk";
}

bool Schema::addColumn(const char* name, uint type) {
	string sname(name);
	std::transform(sname.begin(), sname.end(), sname.begin(), ::tolower);

	if (columnByName.find(sname) != columnByName.end()) {
		return false;
	}


	Column column;

	column.name = sname;
	column.index = columns.size();
	column.type = type;

	columns.push_back(column);

	columnByName[sname] = column;

	return true;
}

Schema Schema::load(const char* schemaFile) {
	ifstream ifs(schemaFile);
	if (!ifs.is_open()) {
		logger.error("Schema not found");
		return Schema();
	}

	Schema schema;
	
	schema.addColumn("seqn", INTEGER);

	string key, value;
	while (true) {
		if (!(ifs >> key >> value)) {
			break;
		}

		uint type = Schema::parseType(value.c_str());

		if (type == Schema::UNKNOWN) {
			logger.error("Unknown type: ", value);
			return Schema();
		}

		if (!schema.addColumn(key.c_str(), type)) {
			logger.error("Column already exists: ", key);
			return Schema();
		}
	}


	return schema;
}
